﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.SharePoint.Administration;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Utilities;
using System.Collections.Specialized;
//using Intellinet.Helper;

namespace DecentTasksReminder.TimerJob
{
    public class EmailReminder
    {
        private string taskName = string.Empty;
        public string TaskName
        {
            get { return taskName; }
            set { taskName = value; }
        }
        private string taskID = string.Empty;
        public string TaskID
        {
            get { return taskID; }
            set { taskID = value; }
        }
        private string url = string.Empty;

        public string Url
        {
            get { return url; }
            set { url = value; }
        }
        private string email = string.Empty;
        public string Email
        {
            get { return email; }
            set { email = value; }
        }
        private string listID = string.Empty;
        public string ListID
        {
            get { return listID; }
            set { listID = value; }
        }

        private string dueDate = string.Empty;
        public string DueDate
        {
            get { return dueDate; }
            set { dueDate = value; }
        }

        private string dayBefore = string.Empty;
        public string DayBefore
        {
            get { return dayBefore; }
            set { dayBefore = value; }
        }

        private string quaterName = string.Empty;
        public string QuaterName
        {
            get { return quaterName; }
            set { quaterName = value; }
        }

    }

    class TasksReminderTimerJob : SPJobDefinition 
    {
        public TasksReminderTimerJob() : base()
        {
        }

        public TasksReminderTimerJob(string jobName, SPService service, SPServer server, SPJobLockType targetType)
            : base(jobName, service, server, targetType)
        {
        }

        public TasksReminderTimerJob(string jobName, SPWebApplication webApplication)
            : base(jobName, webApplication, null, SPJobLockType.ContentDatabase)
        {
            this.Title = "Tasks Reminder Timer Job";
        }

        private void WriteTrace(string message, Exception ex) {         
            //configure how you need, either write to ULS or write to event log         
            if (ex != null)
            {
                SPDiagnosticsService.Local.WriteTrace(0,
                    new SPDiagnosticsCategory("Tasks Reminder Category",
                        Microsoft.SharePoint.Administration.TraceSeverity.Unexpected,
                        EventSeverity.Error),
                        Microsoft.SharePoint.Administration.TraceSeverity.Unexpected, message, ex.StackTrace);
            }
            else
            {
                SPDiagnosticsService.Local.WriteTrace(0,
                    new SPDiagnosticsCategory("Tasks Reminders Category",
                        Microsoft.SharePoint.Administration.TraceSeverity.Unexpected,
                        EventSeverity.Error),
                        Microsoft.SharePoint.Administration.TraceSeverity.Unexpected, message, new string[] {""});
            }
        }

        public void Process(Guid contentDbId)
        {
            string message = "TasksReminderTimerJob.Process\n"; 
            try
            {
                // get a reference to the current site collection's content database
                SPWebApplication webApplication = this.Parent as SPWebApplication;
                SPContentDatabase contentDb = webApplication.ContentDatabases[contentDbId];

                // get a reference to the "ListTimerJob" list in the RootWeb of the first site collection in the content database
                using (SPSite siteCollection = contentDb.Sites[0])
                {
                    foreach (SPWeb web in siteCollection.AllWebs)
                    {
                        //string siteName = GetWebProperty("Audit.SiteName", web.ParentWeb.ParentWeb);
                        string siteName = "";
                        if (web.Name.ToLower() == siteName)
                        {
                            try
                            {
                                //message += "Audit website found; ";
                                //string listName = GetWebProperty("Audit.ListName", web.ParentWeb.ParentWeb);
                                string listName = "DecentTasks";
                                //SPList openItemList = web.Lists[listName];
                                // create a new list Item, set the Title to the current day/time, and update the item
                                //web.AllowUnsafeUpdates = true;

                                List<EmailReminder> remindList = new List<EmailReminder>();
                                List<string> distinctEmail = new List<string>();
                                string previous = string.Empty;
                                // Build a query
                                SPQuery query = new SPQuery();
                                query.Query = string.Concat(
                                               "<Where><Eq>",
                                                  "<FieldRef Name='Status'/>",
                                                  "<Value Type='CHOICE'>Incomplete</Value>",
                                               "</Eq></Where>",
                                               "<OrderBy>",
                                                  "<FieldRef Name='DueDate' Ascending='TRUE' />",
                                               "</OrderBy>");

                                query.ViewFields = string.Concat(
                                   "<FieldRef Name='ID' />",
                                   "<FieldRef Name='Title' />", 
                                   "<FieldRef Name='AssignedTo' />",
                                   "<FieldRef Name='Status' />",
                                   "<FieldRef Name='DueDate' />",
                                   "<FieldRef Name='DaysBefore' />");

                                query.ViewFieldsOnly = false; //Fetch only the data we need

                                // Get data from a list.
                                string listUrl = web.ServerRelativeUrl + "lists/" + listName;
                                SPList openItemList = web.GetList(listUrl);
                                //int folderCount = 0;
                                foreach (SPListItem folderItem in openItemList.Folders)
                                {
                                    if (folderItem.Folder.ItemCount > 0)
                                    {
                                        query.Folder = folderItem.Folder;
                                        query.RecurrenceOrderBy = true;
                                        SPListItemCollection items = openItemList.GetItems(query);
                                        foreach (SPListItem task in items)
                                        {
                                            //message += "task items found:" + task.Title + ";";
                                            if (task["Status"].ToString() == "Incomplete")
                                            {
                                                DateTime dueDate = new DateTime();
                                                if (task["DueDate"] != null)
                                                {
                                                    dueDate = Convert.ToDateTime(task["DueDate"].ToString()).Date;
                                                }

                                                if (dueDate.ToShortDateString() != "1/1/0001")
                                                {
                                                    int intDaysBefore = Convert.ToInt16(task["DaysBefore"].ToString());
                                                    if (intDaysBefore > 0)
                                                    {
                                                        dueDate = dueDate.AddDays(intDaysBefore * -1);
                                                    }

                                                    int comparison = DateTime.Compare(DateTime.Now.Date, dueDate);
                                                    if (comparison >= 0)
                                                    {
                                                        //message += "Date compare greater than 0 ;";
                                                        //dueDate = Convert.ToDateTime(task["DueDate"].ToString()).Date;

                                                        //get all values from AssignedTo field
                                                        SPFieldUserValueCollection assignedTo = (SPFieldUserValueCollection)task["AssignedTo"];
                                                        if (assignedTo != null)
                                                        {
                                                            //message += "Assigned values exists;";
                                                            foreach (SPFieldUserValue fuv in assignedTo)
                                                            {
                                                                EmailReminder remind = new EmailReminder();
                                                                remind.Email = fuv.User.Email;
                                                                if (!previous.Equals(fuv.User.Email) && (distinctEmail.IndexOf(fuv.User.Email) == -1))
                                                                {
                                                                    distinctEmail.Add(fuv.User.Email);
                                                                    //message += " distinct e-mail:" + fuv.User.Email + "; ";
                                                                }
                                                                previous = fuv.User.Email;
                                                                remind.TaskID = task.ID.ToString();
                                                                remind.ListID = task.ParentList.ID.ToString();
                                                                remind.TaskName = task.Title;
                                                                remind.DueDate = Convert.ToDateTime(task["DueDate"].ToString()).ToShortDateString();
                                                                // below Url is breaking as we changed to folder structure
                                                                //remind.Url = task.Web.Url + "/" + task.Url.Substring(0, task.Url.LastIndexOf("/")) + "/" + "DispForm.aspx?ID=" + task.ID.ToString() + "&ContentTypeId=" + task.ContentType.Id.ToString();
                                                                remind.Url = task.Web.Url + "/_layouts/listform.aspx?PageType=4&ListId=" + task.ParentList.ID.ToString("B") + "&ID=" + task.ID.ToString() + "&ContentTypeId=" + task.ParentList.ContentTypes[0].Id;
                                                                remind.QuaterName = folderItem.Folder.Name;
                                                                remindList.Add(remind);
                                                            }
                                                        }
                                                    }
                                                }
                                            }
                                        }   // end of each task
                                    }
                                }
                                if (SendEmailTo(web, remindList, distinctEmail))
                                {
                                    WriteTrace("Tasks OpenItems Reminder sent Successfully.", null);
                                }
                                else
                                {
                                    SPDiagnosticsService.Local.WriteTrace(0,
                                        new SPDiagnosticsCategory("Tasks Reminders Category",
                                        Microsoft.SharePoint.Administration.TraceSeverity.Unexpected,
                                        EventSeverity.Error),
                                        Microsoft.SharePoint.Administration.TraceSeverity.Unexpected, message, new string[] { "Audit Reminders failed to send. please contact Administrator." });
                                }
                            }
                            finally
                            {
                                if (web != null)
                                    web.Dispose();
                            }
                            break; // out of web loop
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                WriteTrace("Tasks Reminder Timer Process Exception:", ex);
            }
            WriteTrace(message, null);
        }

        private static bool SendEmailTo(SPWeb web, List<EmailReminder> remindList, List<string> distinctEmail)
        {
            bool isMailSent = false;
            foreach (string sEmail in distinctEmail)
            {
                StringBuilder sb = new StringBuilder();
                sb.Append("<label>You have one or more items assigned that are incomplete and due. The list of item(s) is below.</label><br/>");
                sb.Append("<p>Click the Title hyperlink to review details of the item.</p><br/>");
                sb.Append("<table border='1' style='border: 1px solid black;border-collapse:collapse;'>");
                sb.Append("<tr><th><font color='Orange'><b>Quarter</b></font></th><th><font color='Orange'><b>Title</b></font></th><th><font color='Orange'><b>Due Date</b></font></th></tr>");
                string preQuarterLabel = string.Empty;
                int j = 0;
                foreach (EmailReminder emailReminder in remindList)
                {
                    if (emailReminder.Email == sEmail)
                    {
                        if (preQuarterLabel != emailReminder.QuaterName)
                        {
                            if (j != 0) sb.Append("<tr><td style='padding:15px;border:none;' colspan='3'/></tr>");
                            sb.Append("<tr>");
                            sb.Append("<td style='padding:5px'>");
                            sb.Append(emailReminder.QuaterName);
                            sb.Append("</td>");
                        }
                        else
                        {
                            sb.Append("<tr>");
                            sb.Append("<td style='padding:5px'>");
                            sb.Append(emailReminder.QuaterName);
                            sb.Append("</td>");
                        }

                        sb.Append("<td  style='padding:5px'>");
                        sb.Append("<a href='");
                        sb.Append(emailReminder.Url);
                        sb.Append("'");
                        sb.Append(" style='text-decoration: none;'");
                        sb.Append(">");
                        sb.Append(emailReminder.TaskName);
                        sb.Append("</a>");
                        sb.Append("</td>");
                        sb.Append("<td  style='padding:5px'>");
                        sb.Append(emailReminder.DueDate);
                        sb.Append("</td>");
                        sb.Append("</tr>");
                        preQuarterLabel = emailReminder.QuaterName;
                        j++;
                    }
                }
                sb.Append("</table>");
                sb.Append("<br/>");
                sb.Append("Note: To stop receiving this reminder email, either mark your items as Complete or push out the Due Date.");
                //message += sb.ToString();

                StringDictionary headers = new StringDictionary();

                headers.Add("to", sEmail);
                //headers.Add("to", "venky@venky-think.com");
                //headers.Add("cc", "cc@email.com");
                //headers.Add("bcc", "");
                //headers.Add("from", "admin@venky-think.com");
                headers.Add("subject", "Reminder – Incomplete Tasks");
                headers.Add("content-type", "text/html");
                string bodyText = sb.ToString(); ;
                if (SPUtility.SendEmail(web, headers, bodyText.ToString())) isMailSent = true;
            }
            return isMailSent;
        }

        public override void Execute(Guid contentDbId)
        {
            try
            {
                if (DateTime.Today.DayOfWeek != DayOfWeek.Saturday && DateTime.Today.DayOfWeek != DayOfWeek.Sunday)    
                {
                    WriteTrace("TasksReminderTimerJob.Execute [Begin]", null);
                    Process(contentDbId);
                    WriteTrace("TasksReminderTimerJob.Execute [End]", null);
                } 
            }
            catch (Exception ex)
            {
                WriteTrace("TasksReminderTimerJob.Execute\nException", ex);
            }
        }

        private DateTime CalculateFutureDate(DateTime fromDate, int numberofWorkDays, ICollection<DateTime> holidays) 
        {     
            var futureDate = fromDate;     
            var daterange = Enumerable.Range(1, numberofWorkDays * 2);     
            var dateSet = daterange.Select (d => futureDate.AddDays(d));     
            var dateSetElim = dateSet.Except(holidays).Except(dateSet.Where( s =>s.DayOfWeek == DayOfWeek.Sunday).Except(dateSet.Where  (s=>s.DayOfWeek==DayOfWeek.Saturday) )); 
            //zero-based array     
            futureDate = dateSetElim.ElementAt(numberofWorkDays-1);     
            return futureDate; 
        }

        //private string GetWebProperty(string Name, SPWeb web)
        //{
        //    string retValue = string.Empty;
        //    if (web != null)
        //    {
        //        if (string.IsNullOrEmpty(web.Properties[Name].ToString()))
        //        {
        //            web.AllowUnsafeUpdates = true;
        //            if (Name.ToLower() == "audit.sitename")
        //                web.Properties.Add(Name, "Audit");
        //            if (Name.ToLower() == "audit.listname")
        //            web.Properties.Add(Name, "TestOpenItems");
        //            web.Properties.Update();
        //            web.AllowUnsafeUpdates = false;
        //        }
        //        retValue = web.Properties[Name].ToString();
        //    }
        //    return retValue;
        //}
    }
}